<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns#">
<head>
    <meta charset='utf-8'>
    <title>Fresco | 自定义View</title>
    <link rel='stylesheet' href='/static/site.css' type='text/css'/>
    <link rel="stylesheet" href='/static/pygments.css' type='text/css'/>
    <link rel='shortcut icon' href='/static/favicon.png'>
    <meta name='viewport' content='width=480'>
    <meta property="og:title" content="自定义View" />
    <meta property="og:site_name" content="fresco">
    <meta property='og:description' content='Fresco is an image management library.'>
    <meta property='og:image' content='http://facebook.github.io/fresco/static/fresco-og-image.png'>
    <meta property='og:url' content="http://facebook.github.io/fresco/docs/writing-custom-views.html">
    
    <meta property='og:type' content='website'>
    
    <script type="text/javascript" src="//use.typekit.net/vqa1hcx.js"></script>
    <script type="text/javascript">{'try{Typekit.load();}catch(e){}'}</script>
    <!-- Google Analytics -->
    <script>
      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
      (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

      ga('create', 'UA-43024238-8', 'auto');
      ga('send', 'pageview');

    </script>
</head>
<body>

<header class='topbar'><nav class='width'>
<a href='/'>
  <img src="/static/fresco-logo.png" class="logo">
</a>
    <ul>
      <li><a href="/docs/index.html#_"
          
          class="active" >
          文档
      </a></li>
      <li><a href="/"
          >
          关于
      </a></li>
      <li><a href="/support.html"
          >
          支持
      </a></li>
      <li><a href="/javadoc">
          API
      </a></li>
      <li><a href="http://github.com/facebook/fresco">GitHub</a>
      <li><a href="/about.html"
          >
      关于本文档</a></li>
    </ul>
</nav></header>


<section class='content'><div class='width'>

<nav class='toc'>
  
    <section>
      <h3>配置和使用</h3>
      <ul>
        
          <li>
            <a href="/docs/download-fresco.html#_">
              下载
            </a>
            
          </li>
        
          <li>
            <a href="/docs/index.html#_">
              配置和开始使用
            </a>
            
          </li>
        
          <li>
            <a href="/docs/concepts.html#_">
              关键概念
            </a>
            
          </li>
        
          <li>
            <a href="/docs/supported-uris.html#_">
              支持的 URIs
            </a>
            
          </li>
        
      </ul>
    </section>
  
    <section>
      <h3>Drawee 指南</h3>
      <ul>
        
          <li>
            <a href="/docs/using-drawees-xml.html#_">
              在XML中使用 Drawees
            </a>
            
          </li>
        
          <li>
            <a href="/docs/using-drawees-code.html#_">
              在Java代码中使用 Drawees
            </a>
            
          </li>
        
          <li>
            <a href="/docs/drawee-components.html#_">
              Drawee的各种效果配置
            </a>
            
          </li>
        
          <li>
            <a href="/docs/scaling.html#_">
              缩放
            </a>
            
          </li>
        
          <li>
            <a href="/docs/rounded-corners-and-circles.html#_">
              圆角/圆圈
            </a>
            
          </li>
        
          <li>
            <a href="/docs/using-controllerbuilder.html#_">
              使用ControllerBuilder
            </a>
            
          </li>
        
          <li>
            <a href="/docs/progressive-jpegs.html#_">
              渐进式JPEG图
            </a>
            
          </li>
        
          <li>
            <a href="/docs/animations.html#_">
              动画图(gif)
            </a>
            
          </li>
        
          <li>
            <a href="/docs/requesting-multiple-images.html#_">
              多图请求及图片复用
            </a>
            
          </li>
        
          <li>
            <a href="/docs/listening-download-events.html#_">
              监听下载事件
            </a>
            
          </li>
        
          <li>
            <a href="/docs/resizing-rotating.html#_">
              缩放和旋转
            </a>
            
          </li>
        
          <li>
            <a href="/docs/modifying-image.html#_">
              图片的修改
            </a>
            
          </li>
        
          <li>
            <a href="/docs/image-requests.html#_">
              图片请求
            </a>
            
          </li>
        
          <li>
            <a href="/docs/writing-custom-views.html#_" class="active">
              自定义View
            </a>
            
          </li>
        
          <li>
            <a href="/docs/gotchas.html#_">
              一些陷阱
            </a>
            
          </li>
        
      </ul>
    </section>
  
    <section>
      <h3>Image Pipeline 指南</h3>
      <ul>
        
          <li>
            <a href="/docs/intro-image-pipeline.html#_">
              什么是Image Pipeline
            </a>
            
          </li>
        
          <li>
            <a href="/docs/configure-image-pipeline.html#_">
              配置Image Pipeline
            </a>
            
          </li>
        
          <li>
            <a href="/docs/caching.html#_">
              缓存的行为控制
            </a>
            
          </li>
        
          <li>
            <a href="/docs/using-image-pipeline.html#_">
              直接使用Image Pipeline
            </a>
            
          </li>
        
          <li>
            <a href="/docs/datasources-datasubscribers.html#_">
              数据源/订阅数据源
            </a>
            
          </li>
        
          <li>
            <a href="/docs/closeable-references.html#_">
              可关闭的引用
            </a>
            
          </li>
        
      </ul>
    </section>
  
    <section>
      <h3>第三方类库</h3>
      <ul>
        
          <li>
            <a href="/docs/using-other-network-layers.html#_">
              自定义网络加载
            </a>
            
          </li>
        
          <li>
            <a href="/docs/using-other-image-loaders.html#_">
              使用其他的Image Loader
            </a>
            
          </li>
        
      </ul>
    </section>
  
</nav>


<article class='withtoc'>
    <h1>
      自定义View
      <a class="edit-page-link" href="https://github.com/liaohuqiu/fresco-docs-cn/blob/docs/docs/01-writing-custom-views.md" target="_blank">编辑和纠错</a>
    </h1>
    <p></p>

    <h3>DraweeHolders</h3>

<p>总有一些时候，<code>DraweeViews</code>是满足不了需求的，在展示图片的时候，我们还需要展示一些其他的内容，或者支持一些其他的操作。在同一个View里，我们可能会想显示一张或者多张图。</p>

<p>在自定义View中，Fresco 提供了两个类来负责图片的展现:</p>

<ul>
<li><code>DraweeHolder</code> 单图情况下用。</li>
<li><code>MultiDraweeHolder</code> 多图情况下用。</li>
</ul>

<h3>自定义View需要完成的事情</h3>

<p>Android 呈现View对象，只有View对象才能得到一些系统事件的通知。<code>DraweeViews</code>
处理这些事件通知，高效地管理内存。使用<code>DraweeHolder</code>时，你需要自己实现这几个方法。</p>

<h4>处理 attach/detach 事件</h4>

<p><strong>如果没按照以下步骤实现的话，很可能会引起内存泄露</strong></p>

<p>当图片不再在View上显示时，比如滑动时View滑动到屏幕外，或者不再绘制，图片就不应该再存在在内存中。Drawees 监听这些事情，并负责释放内存。当图片又需要显示时，重新加载。</p>

<p>这些在<code>DraweeView</code>中是自动的，但是在自定义View中，需要我们自己去操作，如下:</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">DraweeHolder</span> <span class="n">mDraweeHolder</span><span class="o">;</span>

<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onDetachedFromWindow</span><span class="o">()</span> <span class="o">{</span>
  <span class="kd">super</span><span class="o">.</span><span class="na">onDetachedToWindow</span><span class="o">();</span>
  <span class="n">mDraweeHolder</span><span class="o">.</span><span class="na">onDetach</span><span class="o">();</span>
<span class="o">}</span>

<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onStartTemporaryDetach</span><span class="o">()</span> <span class="o">{</span>
  <span class="kd">super</span><span class="o">.</span><span class="na">onStartTemporaryDetach</span><span class="o">();</span>
  <span class="n">mDraweeHolder</span><span class="o">.</span><span class="na">onDetach</span><span class="o">();</span>
<span class="o">}</span>

<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onAttachedToWindow</span><span class="o">()</span> <span class="o">{</span>
  <span class="kd">super</span><span class="o">.</span><span class="na">onAttachedToWindow</span><span class="o">();</span>
  <span class="n">mDraweeHolder</span><span class="o">.</span><span class="na">onAttach</span><span class="o">();</span>
<span class="o">}</span>

<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onFinishTemporaryDetach</span><span class="o">()</span> <span class="o">{</span>
  <span class="kd">super</span><span class="o">.</span><span class="na">onFinishTemporaryDetach</span><span class="o">();</span>
  <span class="n">mDraweeHolder</span><span class="o">.</span><span class="na">onAttach</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div>
<h4>处理触摸事件</h4>

<p>如果你启用了<a href="drawee-components.html#Retry">点击重新加载</a>，在自定义View中，需要这样:</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">onTouchEvent</span><span class="o">(</span><span class="n">MotionEvent</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
  <span class="k">return</span> <span class="n">mDraweeHolder</span><span class="o">.</span><span class="na">onTouchEvent</span><span class="o">(</span><span class="n">event</span><span class="o">)</span> <span class="o">||</span> <span class="kd">super</span><span class="o">.</span><span class="na">onTouchEvent</span><span class="o">(</span><span class="n">event</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div>
<h4>自定义onDraw</h4>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">Drawable</span> <span class="n">drawable</span> <span class="o">=</span> <span class="n">mDraweeHolder</span><span class="o">.</span><span class="na">getHierarchy</span><span class="o">().</span><span class="na">getTopLevelDrawable</span><span class="o">();</span>
<span class="n">drawable</span><span class="o">.</span><span class="na">setBounds</span><span class="o">(...);</span>
</code></pre></div>
<p>否则图片将不会出现</p>

<ul>
<li>不要向下转换这个Drawable</li>
<li>不要变换这个Drawable</li>
</ul>

<h4>其他应该做的</h4>

<ul>
<li>重写 <code>verifyDrawable:</code></li>
</ul>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@Override</span>
<span class="kd">protected</span> <span class="kt">boolean</span> <span class="nf">verifyDrawable</span><span class="o">(</span><span class="n">Drawable</span> <span class="n">who</span><span class="o">)</span> <span class="o">{</span>
  <span class="k">if</span> <span class="o">(</span><span class="n">who</span> <span class="o">==</span> <span class="n">mDraweeHolder</span><span class="o">.</span><span class="na">getHierarchy</span><span class="o">().</span><span class="na">getTopLevelDrawable</span><span class="o">())</span> <span class="o">{</span>
    <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
  <span class="o">}</span>
  <span class="c1">// 对其他Drawable的验证逻辑</span>
<span class="o">}</span>
</code></pre></div>
<ul>
<li>确保<code>invalidateDrawable</code> 处理了图片占用的那块区域。</li>
</ul>

<h3>创建 DraweeHolder</h3>

<p>这同样需要非常小心和细致</p>

<h4>构造函数</h4>

<p>我们推荐如下实现构造函数:</p>

<ul>
<li>重写3个构造函数</li>
<li>在每个构造函数中调用同等签名的父类构造函数，和一个私有的<code>init</code>方法。</li>
<li>在<code>init</code>方法中执行初始化操作。</li>
</ul>

<p>即，不要在构造函数中用<code>this</code>来调用另外一个构造。</p>

<p>这样可以保证，不管调用哪个构造，都可以正确地执行初始化流程。然后在<code>init</code>方法中创建holder。</p>

<h4>创建 Holder</h4>

<p>如果有可能，只在View创建时，创建Drawees。创建DraweeHierarchy开销较大，最好只做一次。</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">class</span> <span class="nc">CustomView</span> <span class="kd">extends</span> <span class="n">View</span> <span class="o">{</span>
  <span class="n">DraweeHolder</span><span class="o">&lt;</span><span class="n">GenericDraweeHierarchy</span><span class="o">&gt;</span> <span class="n">mDraweeHolder</span><span class="o">;</span>

  <span class="c1">// constructors following above pattern</span>

  <span class="kd">private</span> <span class="kt">void</span> <span class="nf">init</span><span class="o">()</span> <span class="o">{</span>
    <span class="n">GenericDraweeHierarchy</span> <span class="n">hierarchy</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">GenericDraweeHierarchyBuilder</span><span class="o">(</span><span class="n">getResources</span><span class="o">());</span>
      <span class="o">.</span><span class="na">set</span><span class="o">...</span>
      <span class="o">.</span><span class="na">set</span><span class="o">...</span>
      <span class="o">.</span><span class="na">build</span><span class="o">();</span>
    <span class="n">mDraweeHolder</span> <span class="o">=</span> <span class="n">DraweeHolder</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">hierarchy</span><span class="o">,</span> <span class="n">context</span><span class="o">);</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div>
<h4>设置要显示的图片</h4>

<p>使用<a href="using-controllerbuilder.html">controller builder</a>创建DraweeController，然后调用holder的<code>setController</code>方法，而不是设置给自定义View。</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">DraweeController</span> <span class="n">controller</span> <span class="o">=</span> <span class="n">Fresco</span><span class="o">.</span><span class="na">newControllerBuilder</span><span class="o">()</span>
    <span class="o">.</span><span class="na">setUri</span><span class="o">(</span><span class="n">uri</span><span class="o">)</span>
    <span class="o">.</span><span class="na">setOldController</span><span class="o">(</span><span class="n">mDraweeHolder</span><span class="o">.</span><span class="na">getController</span><span class="o">())</span>
    <span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="n">mDraweeHolder</span><span class="o">.</span><span class="na">setController</span><span class="o">(</span><span class="n">controller</span><span class="o">);</span>
</code></pre></div>
<h3>MultiDraweeHolder</h3>

<p>和<code>DraweeHolder</code>相比，<code>MultiDraweeHolder</code>有 <code>add</code>, <code>remove</code>, <code>clear</code>
等方法可以操作Drawees。如下:</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">MultiDraweeHolder</span><span class="o">&lt;</span><span class="n">GenericDraweeHierarchy</span><span class="o">&gt;</span> <span class="n">mMultiDraweeHolder</span><span class="o">;</span>

<span class="kd">private</span> <span class="kt">void</span> <span class="nf">init</span><span class="o">()</span> <span class="o">{</span>
  <span class="n">GenericDraweeHierarchy</span> <span class="n">hierarchy</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">GenericDraweeHierarchyBuilder</span><span class="o">(</span><span class="n">getResources</span><span class="o">());</span>
    <span class="o">.</span><span class="na">set</span><span class="o">...</span>
    <span class="o">.</span><span class="na">build</span><span class="o">();</span>
  <span class="n">mMultiDraweeHolder</span> <span class="o">=</span> <span class="k">new</span> <span class="n">MultiDraweeHolder</span><span class="o">&lt;</span><span class="n">GenericDraweeHierarchy</span><span class="o">&gt;();</span>
  <span class="n">mMultiDraweeHolder</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="k">new</span> <span class="n">DraweeHolder</span><span class="o">&lt;</span><span class="n">GenericDraweeHierarchy</span><span class="o">&gt;(</span><span class="n">hierarchy</span><span class="o">,</span> <span class="n">context</span><span class="o">));</span>
  <span class="c1">// repeat for more hierarchies</span>
<span class="o">}</span>
</code></pre></div>
<p>同样，也需要处理系统事件，设置声音等等，就想处理单个<code>DraweeHolder</code>那样。</p>


    <div class="docs-prevnext">
      
        <a href="/docs/image-requests.html#_">&larr; 上一页</a>
      
      
        <a class="right" href="/docs/gotchas.html#_">下一页 &rarr;</a>
      
    </div>

    <a id="_"></a>
</article>

</div></section>
<footer><div class='width'>
    &copy; Copyright 2015, Facebook Inc.
</div></footer>

<script src="/static/linkify.js"></script>
<!-- Google Analytics -->
</body>
</html>

